﻿using HarfBuzzSharp;
using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using LightCAD.Three;
using netDxf.Entities;
using SkiaSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using LightCAD.MathLib;

namespace LightCAD.Drawing.Actions
{
    public class DimDiameterAction : ElementAction
    {
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;

        static DimDiameterAction()
        {
            CommandName = "DIMDIAMETER";
            CreateMethods = new LcCreateMethod[1];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "DDI",
                Description = "DIMDIAMETER",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="Step0", Options="选择圆或圆弧:" },
                }
            };
            
        }

        internal static void Initilize()
        {
            ElementActions.DimDiametric = new DimDiameterAction();
            LcDocument.ElementActions.Add(BuiltinElementType.DimDiametric, ElementActions.DimDiametric);
        }

        private PointInputer inputer { get; set; }

        private Vector2 point;
        private Vector2 endpoint;
        private Vector2 center;
        private double raduis;
    
        public DimDiameterAction() { }
        public DimDiameterAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令 ：DDI");
        }
        private LcCreateMethod GetMethod(string method)
        {
            if (method == null) return CreateMethods[0];
            var getted= CreateMethods.FirstOrDefault((m) => m.Name == method);
            if (getted == null)
                return CreateMethods[0];
            else
                return getted;
        }
        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            //this.Segments = new List<RolineSegment>();
            var curMethod = SetCurMethod(CreateMethods, 0);
            var ElementInputer = new ElementInputer(this.docEditor);
            this.inputer = new PointInputer(this.docEditor);
            Step0:
            var step0 = curMethod.Steps[0];


            var result0 = await ElementInputer.Execute(step0.Options);
            if (ElementInputer.isCancelled) { this.Cancel(); return; }
            // zcb: 增加Res0为空的判定
            if (result0 == null)
            {
                this.Cancel();
                goto End;
            }
            if (result0.ValueX == null)
            {
                goto Step0;
            }
            else
            {
                LcElement element = (LcElement)result0.ValueX;
                this.point = (Vector2)result0.Extent;
                if (CreateSelects(element))
                {
                    //记住圆的圆心点 以及半径
                    if (element is LcCircle||element is LcArc)
                    {
                        if (element is LcCircle)
                        {
                            var circle = element as LcCircle;
                            this.center = circle.Center;
                            this.raduis = circle.Radius;
                            #region
                            LcLine lcline = new LcLine(circle.Center, this.point);
                            //需要移动的向量方向
                            Vector2 direction = new Vector2();
                            //需要移动的距离
                            double dis = Math.Abs(lcline.Length - this.raduis);
                            if (lcline.Length > this.raduis)
                            {
                                //向内延伸
                                direction = new Vector2(this.center.X - this.point.X, this.center.Y - this.point.Y);
                            }
                            else if (lcline.Length < this.raduis)
                            {
                                //向外部延伸
                                direction = new Vector2(this.point.X - this.center.X, this.point.Y - this.center.Y);
                            }
                            if (direction.Length() != 0)
                            {
                                //新的移动后的点位
                                Vector2 lidisptpos = this.point + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                                this.point = lidisptpos;
                            }
                            #endregion
                        }
                        else 
                        {
                           var  circle = element as LcArc;
                            this.center = circle.Center;
                            this.raduis = circle.Radius;
                            #region
                            LcLine lcline = new LcLine(circle.Center, this.point);
                            //需要移动的向量方向
                            Vector2 direction = new Vector2();
                            //需要移动的距离
                            double dis = Math.Abs(lcline.Length - this.raduis);
                            if (lcline.Length > this.raduis)
                            {
                                //向内延伸
                                direction = new Vector2(this.center.X - this.point.X, this.center.Y - this.point.Y);
                            }
                            else if (lcline.Length < this.raduis)
                            {
                                //向外部延伸
                                direction = new Vector2(this.point.X - this.center.X, this.point.Y - this.center.Y);
                            }
                            if (direction.Length() != 0)
                            {
                                //新的移动后的点位
                                Vector2 lidisptpos = this.point + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                                this.point = lidisptpos;
                            }
                            #endregion
                        }





                        this.endpoint = PointRotate(center, this.point, 180);

                        //将数据加入到element中
                        //this.vportRt.ActiveElementSet.AddDimDiametric(this.point, endpoint, raduis.ToString());
                        CreateDimElement();
                        goto End;

                    }
                }
                else
                {
                    goto Step0;
                }
            }
  
            End:
            this.EndCreating();

        }
        private void CreateDimElement()
        {
            var doc = this.docRt.Document;
            DocumentManager.CurrentRecorder.BeginAction("DimDiameter");
            var dimDiametric = doc.CreateObject<DimDiametric>();
            dimDiametric.Start = this.point;
            dimDiametric.End = this.endpoint;
            // DimDiametric.Dimtext =(this.raduis*2).ToString("0.00");
            dimDiametric.Center = this.center;
           


            LcText text = doc.CreateObject<LcText>();
            text.Start = this.point;
            text.TextStart = this.point;
            text.Heigh = 500;// this.raduis * 2 / 20 < 1 ? 1 : Math.Round(this.raduis * 2 / 20);
            text.Text = (this.raduis * 2).ToString("0.00");
            text.Rotate = 180 / Math.PI * (this.point - this.endpoint).Angle();
            text.Alignment = "左对齐";
            text.Widthfactor = 1;
            text.Tilt = 0;

            dimDiametric.Dimtext = text;
            doc.ModelSpace.InsertElement(dimDiametric);

            this.docRt.Action.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
        }
       

        /// <summary>
        /// 选中的对象
        /// </summary>
        /// <param name="elements"></param>
        /// <returns></returns>
        private bool CreateSelects(LcElement elements)
        {

         
                if (elements is LcCircle|| elements is LcArc) {
                    return true;

                }
               
            return false;

        }


        /// <summary>
        /// 对一个坐标点按照一个中心进行旋转
        /// </summary>
        /// <param name="center">中心点</param>
        /// <param name="p1">要旋转的点</param>
        /// <param name="angle">旋转角度，笛卡尔直角坐标</param>
        /// <returns></returns>
        private Vector2 PointRotate(Vector2 center, Vector2 p1, double angle)
        {
            Vector2 tmp = new Vector2();
            double angleHude = angle * Math.PI / 180;/*角度变成弧度*/
            double x1 = (p1.X - center.X) * Math.Cos(angleHude) + (p1.Y - center.Y) * Math.Sin(angleHude) + center.X;
            double y1 = -(p1.X - center.X) * Math.Sin(angleHude) + (p1.Y - center.Y) * Math.Cos(angleHude) + center.Y;
            tmp.X = (int)x1;
            tmp.Y = (int)y1;
            return tmp;
        }
        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
        }
       
        

        public override void CreateElement(LcElement element, Matrix3 matrix)
        {
            //DocumentManager.CurrentRecorder.BeginAction("Circle");
            //var dim = element as DimDiametric;
            //this.vportRt.ActiveElementSet.AddDimDiametric(matrix.MultiplyPoint(dim.Start), matrix.MultiplyPoint(dim.End),dim.Dimtext);
            //DocumentManager.CurrentRecorder.EndAction();
        }
        public override void CreateElement(LcElement element,Vector2 basePoint, double scaleFactor)
        {
            //var circle = element as LcCircle;
            //Matrix3d matrix3 = Matrix3d.Scale(scaleFactor, basePoint);
            //this.vportRt.ActiveElementSet.AddCircle(matrix3.MultiplyPoint(circle.Center), circle.Radius * scaleFactor);
        }
        public override void CreateElement(LcElement element, Vector2 basePoint, Vector2 scaleVector)
        {
            //var circle = element as LcCircle;
            //Matrix3d matrix3 = Matrix3d.Scale(scaleVector, basePoint);
            //this.vportRt.ActiveElementSet.AddCircle(matrix3.MultiplyPoint(circle.Center), circle.Radius * Vector2d.Distance(basePoint, scaleVector));
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var dim = element as DimDiametric;
          
          
            var mstart= matrix.MultiplyPoint(dim.Start);
            var mend = matrix.MultiplyPoint(dim.End);
            var mtext =  dim.Dimtext;
            var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
            var end= this.vportRt.ConvertWcsToScr(mend).ToSKPoint();
            //get Layer color 
            //bool isDragCopy = (matrix != Matrix3d.Zero);
            var pen = this.GetDrawPen(dim);

            Vector2 direction = new Vector2(dim.Start.X - dim.End.X, dim.Start.Y - dim.End.Y);
            double dis = Math.Abs(dim.Dimtext.Width);
            Vector2 lidisptpos = dim.Start + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
            //

            var newend = this.vportRt.ConvertWcsToScr(lidisptpos).ToSKPoint();

           

            if (pen == Runtime.Constants.defaultPen)
            {
                //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                {
                    canvas.DrawLine(start, end, elePen);
                    canvas.DrawLine(start, newend, elePen);

                }
            }
            else
            {
                canvas.DrawLine(start, end, pen);
                canvas.DrawLine(start, newend, pen);
               
            }
            var eleAction = (dim.Dimtext.RtAction as ElementAction);
            dim.Dimtext.Start = dim.Start;
            dim.Dimtext.Rotate = 180 / Math.PI * (dim.Start - dim.End).Angle();
            dim.Dimtext.Text = Math.Abs((dim.Start - dim.End).Length()).ToString("0.00");

            eleAction.SetViewport(this.vportRt).Draw(canvas, dim.Dimtext, matrix);
            #region
            var path = DrawArrow(dim.Start, dim.End);
            var path1 = DrawArrow(dim.End, dim.Start);
            using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
            {
                //elePen.Color = SKColors.Red;
                elePen.Style = SKPaintStyle.Fill;
                elePen.IsAntialias = true;
                elePen.StrokeWidth = 2;
                //绘制路径
                canvas.DrawPath(path, elePen);
                canvas.DrawPath(path1, elePen);
            }
            #endregion

        }
        //public override void Scale(Vector2d basePoint, double scaleFactor)
        //{
        //    Matrix3d matrix3 = Matrix3d.Scale(scaleFactor, basePoint);
        //    //this.Set(matrix3.MultiplyPoint(this.point), matrix3.MultiplyPoint(this.endpoint));
           
        //}
        private SKPath DrawArrow(Vector2 start, Vector2 end, double extraAngle = 180)
        {
            LcLine lcline = new LcLine();
            lcline.Start = start;
            lcline.End = end;
            var radian = lcline.Angle;

            var startve = new Vector2(lcline.Start.X, lcline.Start.Y);
            var arrowtwove = new Vector2(lcline.Start.X + 100, lcline.Start.Y + 30);
            var arrowendve = new Vector2(lcline.Start.X + 100, lcline.Start.Y - 30);
            var angle = Utils.RadianToDegree(radian) + extraAngle;
            arrowtwove = Vector2.Rotate(arrowtwove, startve, angle);
            arrowendve = Vector2.Rotate(arrowendve, startve, angle);

            var pointone = this.vportRt.ConvertWcsToScr(startve).ToSKPoint();
            var pointtwo = this.vportRt.ConvertWcsToScr(arrowtwove).ToSKPoint();
            var pointthree = this.vportRt.ConvertWcsToScr(arrowendve).ToSKPoint();

            var path = new SKPath();
            path.FillType = SKPathFillType.EvenOdd;
            //外圈 顺时针
            path.MoveTo((float)pointone.X, (float)pointone.Y);    //起点
            path.LineTo((float)pointtwo.X, (float)pointtwo.Y);
            path.LineTo((float)pointthree.X, (float)pointthree.Y);
            path.Close();
            return path;
        }


        public override void DrawAuxLines(SKCanvas canvas)
        {
            //var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            //var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
        


        }

        private void DrawAuxLine(SKCanvas canvas, Vector2 p0, Vector2 p1)
        {
            var sk_pre = this.vportRt.ConvertWcsToScr(p0).ToSKPoint();
            var sk_p = this.vportRt.ConvertWcsToScr(p1).ToSKPoint();
            //辅助元素的颜色 
            canvas.DrawLine(sk_pre, sk_p, new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true });
            //辅助曲线的颜色，包括辅助长度，辅助角度等
        }
        #region Grip
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var dim = element as DimDiametric;

            var grips = new List<ControlGrip>();
            var gripStartr = new ControlGrip
            {
                Element = dim,
                Name = "Start",
                Position = dim.Start
            };
            grips.Add(gripStartr);

            var gripEnd = new ControlGrip
            {
                Element = dim,
                Name = "End",
                Position = dim.End
            };
            grips.Add(gripEnd);


            return grips.ToArray();
        }
        private string _gripName;
        private Vector2 _position;
        private DimDiametric _dim;


        /// <summary>  
        /// 根据余弦定理求两个线段夹角  
        /// </summary>  
        /// <param name="o">端点</param>  
        /// <param name="s">start点</param>  
        /// <param name="e">end点</param>  
        /// <returns></returns>  
        public double SEAngle(Vector2 o, Vector2 s, Vector2 e)
        {

            var so = new Vector2(s.X - o.X, s.Y - o.Y);
            var eo = new Vector2(e.X - o.X, e.Y - o.Y);
            return (so.Angle() - eo.Angle()) /Math.PI*180;

        }


        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var dim= element as DimDiametric;

            _dim = dim;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
             


            }
            else
            {
                if (gripName == "Start")
                {
                    //计算停止时 点与结束点的夹角
                    Vector2 newstart = PointRotate(_dim.Center, _dim.Start, SEAngle(_dim.Center, _dim.Start, position));
                    Vector2 newend = PointRotate(_dim.Center, newstart, 180);
                    dim.Set(value:"Start",start: newstart, end: newend);

                    //dim.Set(Start:position);
                }
                
                else
                {
                    //Vector2d newend = PointRotate(_dim.Center, _dim.End, SEAngle(_dim.Center, _dim.End, position));
                    Vector2 newstart = PointRotate(_dim.Center, position, 180);
                    dim.Set(value: "End", start: newstart, end: position);
                    //dim.Set(End: position);
                }
            }
        }


        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_dim == null) return;
            //直径
            var diameter = distance(_dim.Start, _dim.End);

            #region  
            var start = this.vportRt.ConvertWcsToScr(_dim.Start);
            var end = this.vportRt.ConvertWcsToScr(_dim.End);

            if (_gripName == "End")
            {
                //end = PointRotate(_dim.Center, _dim.Start, 180);
                //start = this.vportRt.ConvertWcsToScr(_position);

                Vector2 newstart = PointRotate(_dim.Center, _position, 180);

                Vector2 direction = new Vector2(newstart.X - _position.X, newstart.Y - _position.Y);
                double dis2 = Math.Abs(_dim.Dimtext.Width);
                Vector2 lidisptpos2 = newstart + (new Vector2(direction.X * dis2, direction.Y * dis2)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));

                var newend2 = this.vportRt.ConvertWcsToScr(lidisptpos2).ToSKPoint();

                var start1 = this.vportRt.ConvertWcsToScr(newstart);
                var end1 = this.vportRt.ConvertWcsToScr(_position);
                canvas.DrawLine(start1.ToSKPoint(), end1.ToSKPoint(), Runtime.Constants.draggingPen);

                canvas.DrawLine(start1.ToSKPoint(), newend2, Runtime.Constants.draggingPen);

                var path = DrawArrow(newstart, _position);
                var path1 = DrawArrow(_position, newstart);
                using (var elePen = new SKPaint { Color = new SKColor(_dim.GetColorValue()), IsStroke = true })
                {
                    //elePen.Color = SKColors.Red;
                    elePen.Style = SKPaintStyle.Fill;
                    elePen.IsAntialias = true;
                    elePen.StrokeWidth = 2;
                    //绘制路径
                    canvas.DrawPath(path, elePen);
                    canvas.DrawPath(path1, elePen);
                }
                //var eleAction = (_dim.Dimtext.RtAction as ElementAction);
                //_dim.Dimtext.Start = newstart;
                //_dim.Dimtext.Rotate = 180 / Math.PI * (newstart - _position).Angle();
                //_dim.Dimtext.Text = Math.Abs((newstart - _position).Length()).ToString("0.00");
                //eleAction.SetViewport(this.vportRt).Draw(canvas, _dim.Dimtext,new Matrix3());
                this.vportRt.DrawText(newstart, _dim.Dimtext.TextStart, _dim.Dimtext.Heigh, 180 / Math.PI * (newstart - _position).Angle(), Math.Abs((newstart - _position).Length()).ToString("0.00"), _dim.Dimtext.Tilt,
                    _dim.Dimtext.Typeface, _dim.Dimtext.Widthfactor, _dim.Dimtext.Alignment, new Matrix3(), canvas, Runtime.Constants.draggingPen);




                //diameter = distance(_position, _dim.End);
            }



            if (_gripName == "Start")
            {
                //start = PointRotate(_dim.Center, _dim.End, 180);
                //end = this.vportRt.ConvertWcsToScr(_position);

                Vector2 newstart = PointRotate(_dim.Center, _dim.Start, SEAngle(_dim.Center, _dim.Start, _position));
                Vector2 newend = PointRotate(_dim.Center, newstart, 180);

                var start1 = this.vportRt.ConvertWcsToScr(newstart);
                var end1 = this.vportRt.ConvertWcsToScr(newend);
                canvas.DrawLine(start1.ToSKPoint(), end1.ToSKPoint(), Runtime.Constants.draggingPen);

                Vector2 direction = new Vector2(newstart.X - newend.X, newstart.Y - newend.Y);
                double dis2 = Math.Abs(_dim.Dimtext.Width);
                Vector2 lidisptpos2 = newstart + (new Vector2(direction.X * dis2, direction.Y * dis2)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));

                var newend2 = this.vportRt.ConvertWcsToScr(lidisptpos2).ToSKPoint();

                

                canvas.DrawLine(start1.ToSKPoint(), newend2, Runtime.Constants.draggingPen);

                var path = DrawArrow(newstart, newend);
                var path1 = DrawArrow(newend, newstart);
                using (var elePen = new SKPaint { Color = new SKColor(_dim.GetColorValue()), IsStroke = true })
                {
                    //elePen.Color = SKColors.Red;
                    elePen.Style = SKPaintStyle.Fill;
                    elePen.IsAntialias = true;
                    elePen.StrokeWidth = 2;
                    //绘制路径
                    canvas.DrawPath(path, elePen);
                    canvas.DrawPath(path1, elePen);
                }
                
                this.vportRt.DrawText(newstart, _dim.Dimtext.TextStart,_dim.Dimtext.Heigh, 180 / Math.PI * (newstart - newend).Angle(), _dim.Dimtext.Text, _dim.Dimtext.Tilt,
                    _dim.Dimtext.Typeface,_dim.Dimtext.Widthfactor,_dim.Dimtext.Alignment, new Matrix3(), canvas, Runtime.Constants.draggingPen);

               // var eleAction = (_dim.Dimtext.RtAction as ElementAction);
               // _dim.Dimtext.Start = newstart;
               // _dim.Dimtext.Rotate = 180 / Math.PI * (newstart - newend).Angle();
               //// _dim.Dimtext.Text = Math.Abs((newstart - newend).Length()).ToString("0.00");
               // eleAction.SetViewport(this.vportRt).Draw(canvas, _dim.Dimtext, new Matrix3());
            }
          

            //辅助线
            canvas.DrawLine(start.ToSKPoint(), end.ToSKPoint(), Runtime.Constants.draggingPen);
            #endregion






        }

        #endregion
        public static double distance(Vector2 p1, Vector2 p2)
        {
            double result = 0;
            result = Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
            return result;

        }
        public override List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>();
            
        }
    }
}
